package com.haima.sage.bigdata.api.process.impl;

import com.haima.sage.bigdata.api.common.DbUtils;
import com.haima.sage.bigdata.api.entity.storage.Storage;
import com.haima.sage.bigdata.api.exception.ValidateException;
import com.haima.sage.bigdata.api.process.ParamProcess;
import com.haima.sage.bigdata.api.vo.param.ListParam;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.sql.Connection;

public class ListParamProcess extends ParamProcess {
    private static final Logger LOG = LogManager.getLogger(ListParamProcess.class);
    private ListParam param;

    public ListParamProcess(ListParam param) {
        this.param = param;
    }


    protected Object executeES(Storage storage, String table, String pattern,Integer maxBatchSize) throws Exception{
        super.executeES(storage, table, pattern, maxBatchSize);
        String entity = genEsJson(table,maxBatchSize,storage);
        Object obj = null;
        try {
            obj = esUtils.esPost(storage, table, maxBatchSize, entity, param);
        } catch (Exception e) {
            throw new Exception("ES post error!");
        }
        return obj;
    }

    protected Object executeRedis(Storage storage, String table, Integer maxBatchSize) {
        return null;
    }

    @Override
    public void validate() throws ValidateException {
        super.validate(param);
        validateFields(param.getFields());
        validateOffset(param.getOffset());
        validateLimit(param.getLimit());
        validateOrderBy(param.getOrderBy());
    }

    private void validateOffset(Integer offset) throws ValidateException {
        if (offset == null) {
            throw new ValidateException("offset must not empty", "offset不能为空");
        }
    }

    protected Object executeDB(Storage storage, String table, Integer maxBatchSize) throws Exception {
        String sql = genSQL(table, maxBatchSize);
        LOG.debug("sql:{}", sql);
        try (Connection conn = DbUtils.getConnection(storage.getId())) {
            return DbUtils.getListResult(sql, conn, maxBatchSize);
        }
    }

    /**
     * select * from ${table}
     * where ${where}
     * sort by ${sortBys}
     * limit ${limit} offset ${offset};
     */
    private String genSQL(String table, Integer maxBatchSize) throws ValidateException {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT ");
        appendFields(sql, param.getFields());
        sql.append(" FROM ").append(table);
        // where
        appendWhere(sql, param.getWhere());
        // order by
        appendOrderBy(sql, param.getOrderBy());
        // limit
        appendLimit(sql, param.getLimit(), maxBatchSize);
        // offset
        appendOffset(sql);
        return sql.toString();
    }

    private void appendOffset(StringBuilder sql) {
        if (param.getOffset() != null) {
            sql.append(" offset ").append(param.getOffset());
        }
    }

    /**
     * select * from ${table}
     * where ${where}
     * sort by ${sortBys}
     * limit ${limit} offset ${offset};
     */
    private String genEsJson(String table, Integer maxBatchSize,Storage storage)throws Exception{
        StringBuilder jsonBody = new StringBuilder();
        jsonBody.append("{");
        //_source 字段
        if (param.getFields() != null)
        esUtils.appendField(jsonBody,param.getFields());

        //from
        esUtils.appendOffset(jsonBody, param.getOffset());

        //size
        esUtils.appendLimit(jsonBody, param.getLimit(), maxBatchSize);
        //query
        if(param.getWhere() != null) {
            jsonBody.append("\"query\":");
            esUtils.appendWhere(jsonBody, param.getTable(), storage, param.getWhere());
        }
        //sort
        esUtils.appendOrderBy(jsonBody,param,storage);
        jsonBody.deleteCharAt(jsonBody.length() - 1);
        jsonBody.append("}");
        LOG.info(jsonBody.toString());
        return jsonBody.toString();
    }

}
